﻿using System;
using Glue;
using Glue.Internals.Verification;
using Xunit;

namespace GlueTests.MapperVerificationTests
{
    public class When_using_coverters
    {
        private readonly Mapping<DomainPerson, GuiPerson> mapping;
        private readonly MapperVerification<DomainPerson, GuiPerson> verification;

        public class DomainPerson
        {
            public String StringProperty { get; set; }
            public int IntProperty { get; set; }
            public short ShortProperty { get; set; }
            public double DoubleProperty { get; set; }
            public float FloatProperty { get; set; }
        }

        public class GuiPerson
        {
            public String StringProperty { get; set; }
            public int IntProperty { get; set; }
            public long LongProperty { get; set; }
            public bool BoolProperty { get; set; }
            public Byte ByteProperty { get; set; }
            public SByte SByteProperty { get; set; }
            public Char CharProperty { get; set; }
            public decimal DecimalProperty { get; set; }
            public double DoubleProperty { get; set; }
            public float FloatProperty { get; set; }
            public uint UIntProperty { get; set; }
            public ulong ULongProperty { get; set; }
            public short ShortProperty { get; set; }
            public ushort UShortProperty { get; set; }

            private int needSpecialConverterfield;

            public int NeedSpecialConverterProperty
            {
                get { return needSpecialConverterfield; }
                set 
                { 
                    if (value < 0 || value > 3)
                        throw new Exception("I am not satisfied with " + value);
                    needSpecialConverterfield = value;
                }
            }
        }

        public When_using_coverters()
        {
            mapping = new Mapping<DomainPerson, GuiPerson>();
            verification = new MapperVerification<DomainPerson, GuiPerson>(mapping);
            
        }

        [Fact]
        public void Should_map_between_same_types()
        {
            mapping.Relate(x => x.StringProperty, y => y.StringProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_int()
        {
            mapping.AddConverter(Converting.BetweenIntAndString());
            mapping.Relate(x=>x.StringProperty,y=>y.IntProperty);
            AssertMapping();            
        }

        [Fact]
        public void Should_map_between_String_and_long()
        {
            mapping.AddConverter(Converting.BetweenLongAndString());
            mapping.Relate(x => x.StringProperty, y => y.LongProperty);
            AssertMapping();            
        }

        [Fact]
        public void Should_map_between_String_and_bool()
        {
            mapping.AddConverter(Converting.BetweenBoolAndString());
            mapping.Relate(x => x.StringProperty, y => y.BoolProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_byte()
        {
            mapping.AddConverter(Converting.BetweenByteAndString());
            mapping.Relate(x => x.StringProperty, y => y.ByteProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_sbyte()
        {
            mapping.AddConverter(Converting.BetweenSByteAndString());
            mapping.Relate(x => x.StringProperty, y => y.SByteProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_char()
        {
            mapping.AddConverter(Converting.BetweenCharAndString());
            mapping.Relate(x => x.StringProperty, y => y.CharProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_decimal()
        {
            mapping.AddConverter(Converting.BetweenDecimalAndString());
            mapping.Relate(x => x.StringProperty, y => y.DecimalProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_double()
        {
            mapping.AddConverter(Converting.BetweenDoubleAndString());
            mapping.Relate(x => x.StringProperty, y => y.DoubleProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_float()
        {
            mapping.AddConverter(Converting.BetweenFloatAndString());
            mapping.Relate(x => x.StringProperty, y => y.FloatProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_uint()
        {
            mapping.AddConverter(Converting.BetweenUIntAndString());
            mapping.Relate(x => x.StringProperty, y => y.UIntProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_ulong()
        {
            mapping.AddConverter(Converting.BetweenULongAndString());
            mapping.Relate(x => x.StringProperty, y => y.ULongProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_short()
        {
            mapping.AddConverter(Converting.BetweenShortAndString());
            mapping.Relate(x => x.StringProperty, y => y.ShortProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_String_and_ushort()
        {
            mapping.AddConverter(Converting.BetweenUShortAndString());
            mapping.Relate(x => x.StringProperty, y => y.UShortProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_long_and_int()
        {
            mapping.AddConverter(Converting.BetweenIntAndLong());
            mapping.Relate(x => x.IntProperty, y => y.LongProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_long_and_short()
        {
            mapping.AddConverter(Converting.BetweenShortAndLong());
            mapping.Relate(x => x.ShortProperty, y => y.LongProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_int_and_short()
        {
            mapping.AddConverter(Converting.BetweenIntAndShort());
            mapping.Relate(x => x.IntProperty, y => y.ShortProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_double_and_float()
        {
            mapping.AddConverter(Converting.BetweenDoubleAndFloat());
            mapping.Relate(x => x.DoubleProperty, y => y.FloatProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_double_and_decimal()
        {
            mapping.AddConverter(Converting.BetweenDoubleAndDecimal());
            mapping.Relate(x => x.DoubleProperty, y => y.DecimalProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_map_between_float_and_decimal()
        {
            mapping.AddConverter(Converting.BetweenFloatAndDecimal());
            mapping.Relate(x => x.FloatProperty, y => y.DecimalProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_use_custom_randomizer_if_added()
        {
            var random = new Random(Environment.TickCount);
            verification.AddRandomizer(typeof(int), () => random.Next(0, 3));
            mapping.Relate(x => x.IntProperty, y => y.NeedSpecialConverterProperty);
            AssertMapping();
        }

        [Fact]
        public void Should_use_custom_randomizer_if_added_and_mapping_between_different_types()
        {
            var random = new Random(Environment.TickCount);
            verification.AddRandomizer(typeof(short),()=>  (short)random.Next(0,3) );
            mapping.AddConverter(Converting.BetweenIntAndShort());
            mapping.Relate(x => x.ShortProperty, y => y.NeedSpecialConverterProperty);
            AssertMapping();
        }

        private void AssertMapping()
        {
            verification.AssertMapsCorrectlyTowards(new DomainPerson());
            verification.AssertMapsCorrectlyTowards(new GuiPerson());
        }
    }
}
